package com.fine.hair.comm.wx;

import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.fine.hair.comm.redis.RedisService;
import com.fine.hair.comm.exception.BusinessException;
import com.fine.hair.comm.pojo.TxErrData;
import com.fine.hair.comm.pojo.wx.*;
import com.fine.hair.comm.pojo.wx.config.WxMpProperty;
import com.fine.hair.comm.utils.Consts;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.text.MessageFormat;

/**
 * @author junelee
 * @date 2020/6/27 22:27
 * <p>
 * 参考文档
 * https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/union-id.html
 * https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html
 * https://developers.weixin.qq.com/doc/oplatform/Mobile_App/WeChat_Login/Authorized_API_call_UnionID.html
 */
@Slf4j
@Service
public class WxClient {
    private static final String URL_WX_MP_ACCESS_TOKEN = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}";
    private static final String URL_WX_MP_OAUTH_ACCESS_TOKEN = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1}&code={2}&grant_type=authorization_code";
    private static final String URL_USER_INFO = "https://api.weixin.qq.com/sns/userinfo?access_token={0}&openid={1}";
    private static final String URL_GET_TICKET = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={0}&type=jsapi";
    private static final String URL_LIST_WX_MP_USER = "https://api.weixin.qq.com/cgi-bin/user/get?access_token={0}&next_openid={1}";
    private static final String URL_GET_WX_MP_USER_BASIC_INFO = "https://api.weixin.qq.com/cgi-bin/user/info?access_token={0}&openid={1}&lang=zh_CN";
    private static final String URL_SEND_TEMPLATE_MSG = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={0}";
    private static final String URL_CREATE_MENU = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token={0}";
    private static final String URL_UNIFORM_MESSAGE_SEND = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token={0}";
    private static final String URL_SEND = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token={0}";

    private static final String URL_JSCODE_2_SESSION = "https://api.weixin.qq.com/sns/jscode2session?appid={0}&secret={1}&js_code={2}&grant_type=authorization_code";
    public static final String URL_WX_LITE_ACCESS_TOKEN = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}";


    /**
     * TODO 完善 密钥
     */
    @Autowired
    private WxLiteProperty wxLiteProperty;

    @Autowired
    private WxMpProperty wxMpProperty;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private RedisService redisService;

    public TxErrData WxSendTemplateMsg(WxMsgSendData data) {
        String accessTokenUrl = MessageFormat.format(URL_WX_LITE_ACCESS_TOKEN, wxLiteProperty.getAppId(),
                wxLiteProperty.getSecret());
        ResponseEntity<String> res = restTemplate.getForEntity(accessTokenUrl, String.class);

        log.debug("http.status = '{}', body = {}", res.getStatusCode(), res.getBody());
        if (res.getStatusCode() != HttpStatus.OK) {
            log.error("调用微信 URL_WX_LITE_ACCESS_TOKEN 失败. res = {}", res);
            throw new BusinessException("调用微信 URL_WX_LITE_ACCESS_TOKEN 失败");
        }
        System.out.println(res.getBody());

        WxAccessTokenResponse wxAccessTokenResponse = new Gson().fromJson(res.getBody(), WxAccessTokenResponse.class);

        String messageSendUrl = MessageFormat.format(URL_UNIFORM_MESSAGE_SEND, wxAccessTokenResponse.getAccessToken());
        ResponseEntity<String> result = restTemplate.postForEntity(messageSendUrl, data, String.class);
        System.out.println(result.getBody());
        return new Gson().fromJson(result.getBody(), TxErrData.class);

    }


    /**
     * 发送订阅消息
     *
     * @param data
     * @return
     */
    public TxErrData WxSend(WxSendData data) {
        String accessTokenUrl = MessageFormat.format(URL_WX_LITE_ACCESS_TOKEN, wxLiteProperty.getAppId(),
                wxLiteProperty.getSecret());
        ResponseEntity<String> res = restTemplate.getForEntity(accessTokenUrl, String.class);

        log.debug("http.status = '{}', body = {}", res.getStatusCode(), res.getBody());
        if (res.getStatusCode() != HttpStatus.OK) {
            log.error("调用微信 URL_WX_LITE_ACCESS_TOKEN 失败. res = {}", res);
            throw new BusinessException("调用微信 URL_WX_LITE_ACCESS_TOKEN 失败");
        }
        System.out.println(res.getBody());

        WxAccessTokenResponse wxAccessTokenResponse = new Gson().fromJson(res.getBody(), WxAccessTokenResponse.class);

        String messageSendUrl = MessageFormat.format(URL_SEND, wxAccessTokenResponse.getAccessToken());
        ResponseEntity<String> result = restTemplate.postForEntity(messageSendUrl, data, String.class);
        System.out.println(result.getBody());
        return new Gson().fromJson(result.getBody(), TxErrData.class);

    }

    // 订单预约
    public static void orderSubscribe(String openId, String yynr, String scribeTime, String branchName, String branchPhone, String fugw, String id) {
        String accessTokenUrl = MessageFormat.format(URL_WX_LITE_ACCESS_TOKEN, "wx003650c44a4fed51",
                "40857fc1a04b17f4fcc2fc52b271b4ab");
        ResponseEntity<String> res = new RestTemplate().getForEntity(accessTokenUrl, String.class);

        log.debug("http.status = '{}', body = {}", res.getStatusCode(), res.getBody());
        if (res.getStatusCode() != HttpStatus.OK) {
            log.error("调用微信 URL_WX_LITE_ACCESS_TOKEN 失败. res = {}", res);
            throw new BusinessException("调用微信 URL_WX_LITE_ACCESS_TOKEN 失败");
        }
        WxAccessTokenResponse wxAccessTokenResponse = new Gson().fromJson(res.getBody(), WxAccessTokenResponse.class);

        String messageSendUrl = MessageFormat.format(URL_SEND, wxAccessTokenResponse.getAccessToken());
        String data = "{" +
                "\"touser\": \"" + openId + "\"," +
                "\"template_id\": \"6josDr7jRQoQYhUs_HUSrAZLhrjs5hSSDG-SpmeLHiE\"," +
                "\"lang\": \"zh_CN\"," +
                "\"page\": \"pages/my/inside/ApplyLook/ApplyLook?id=" + id + "\"," +
                "\"data\": {" +
                "\"thing1\": {" +
                "\"value\": \"" + yynr + "\"" +
                "}," +
                "\"date2\": {" +
                "\"value\": \"" + scribeTime + "\"" +
                "}," +
                "\"thing6\": {" +
                "\"value\": \"" + branchName + "\"" +
                "}," +
                "\"phone_number7\": {" +
                "\"value\": \"" + branchPhone + "\"" +
                "}," +
                "\"thing11\": {" +
                "\"value\": \"" + fugw + "\"" +
                "}" +
                "}" +
                "}";
        HttpHeaders headers = new HttpHeaders();
        // 防止消息乱码
        MediaType headType = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(headType);
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());
        HttpEntity<String> requestEntity = new HttpEntity<String>(data, headers);
        ResponseEntity<String> result = new RestTemplate().postForEntity(messageSendUrl, requestEntity, String.class);
        log.debug("http.status = '{}', body = {}", result.getStatusCode(), result.getBody());
    }

    // 订单取消
    public static void orderCancel(String openId, String yynr, String yyTime, String branchName, String remark, String id) {
        String accessTokenUrl = MessageFormat.format(URL_WX_LITE_ACCESS_TOKEN, "wx003650c44a4fed51",
                "40857fc1a04b17f4fcc2fc52b271b4ab");
        ResponseEntity<String> res = new RestTemplate().getForEntity(accessTokenUrl, String.class);

        log.debug("http.status = '{}', body = {}", res.getStatusCode(), res.getBody());
        if (res.getStatusCode() != HttpStatus.OK) {
            log.error("调用微信 URL_WX_LITE_ACCESS_TOKEN 失败. res = {}", res);
            throw new BusinessException("调用微信 URL_WX_LITE_ACCESS_TOKEN 失败");
        }
        WxAccessTokenResponse wxAccessTokenResponse = new Gson().fromJson(res.getBody(), WxAccessTokenResponse.class);

        String messageSendUrl = MessageFormat.format(URL_SEND, wxAccessTokenResponse.getAccessToken());
        String data = "{" +
                "\"touser\": \"" + openId + "\"," +
                "\"template_id\": \"LC0EZKc1fCgOrEqgph6VFE8fXUo832NaCg7hT15ae18\"," +
                "\"page\": \"pages/my/inside/ApplyLook/ApplyLook?id=" + id + "\"," +
                "\"lang\": \"zh_CN\"," +
                "\"data\": {" +
                "\"thing1\": {" +
                "\"value\": \"" + yynr + "\"" +
                "}," +
                "\"time2\": {" +
                "\"value\": \"" + yynr + "\"" +
                "}," +
                "\"thing3\": {" +
                "\"value\": \"" + branchName + "\"" +
                "}," +
                "\"thing4\": {" +
                "\"value\": \"" + remark + "\"" +
                "}" +
                "}" +
                "}";
        HttpHeaders headers = new HttpHeaders();
        // 防止消息乱码
        MediaType headType = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(headType);
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());
        HttpEntity<String> requestEntity = new HttpEntity<String>(data, headers);
        ResponseEntity<String> result = new RestTemplate().postForEntity(messageSendUrl, requestEntity, String.class);
        log.debug("http.status = '{}', body = {}", result.getStatusCode(), result.getBody());
    }

    // 订单完成
    public static void orderSecc(String openId, String succTime, String orderStatus, String serverName, String time, String id) {
        String accessTokenUrl = MessageFormat.format(URL_WX_LITE_ACCESS_TOKEN, "wx003650c44a4fed51",
                "40857fc1a04b17f4fcc2fc52b271b4ab");
        ResponseEntity<String> res = new RestTemplate().getForEntity(accessTokenUrl, String.class);

        log.debug("http.status = '{}', body = {}", res.getStatusCode(), res.getBody());
        if (res.getStatusCode() != HttpStatus.OK) {
            log.error("调用微信 URL_WX_LITE_ACCESS_TOKEN 失败. res = {}", res);
            throw new BusinessException("调用微信 URL_WX_LITE_ACCESS_TOKEN 失败");
        }
        WxAccessTokenResponse wxAccessTokenResponse = new Gson().fromJson(res.getBody(), WxAccessTokenResponse.class);

        String messageSendUrl = MessageFormat.format(URL_SEND, wxAccessTokenResponse.getAccessToken());
        String data = "{" +
                "\"touser\": \"" + openId + "\"," +
                "\"template_id\": \"svHjJMUwhQ_xh4OxzeH-mJi-hwzIe8PTq8-0KtfnlVE\"," +
                "\"page\": \"pages/my/inside/ApplyLook/ApplyLook?id=" + id + "\"," +
                "\"lang\": \"zh_CN\"," +
                "\"data\": {" +
                "\"time2\": {" +
                "\"value\": \"" + succTime + "\"" +
                "}," +
                "\"thing3\": {" +
                "\"value\": \"订单完成通知\"" +
                "}," +
                "\"phrase5\": {" +
                "\"value\": \"" + orderStatus + "\"" +
                "}," +
                "\"thing6\": {" +
                "\"value\": \"" + serverName + "\"" +
                "}," +
                "\"time7\": {" +
                "\"value\": \"" + time + "\"" +
                "}" +
                "}" +
                "}";
        HttpHeaders headers = new HttpHeaders();
        // 防止消息乱码
        MediaType headType = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(headType);
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());
        HttpEntity<String> requestEntity = new HttpEntity<String>(data, headers);
        ResponseEntity<String> result = new RestTemplate().postForEntity(messageSendUrl, requestEntity, String.class);
        log.debug("http.status = '{}', body = {}", result.getStatusCode(), result.getBody());
    }


    public WxCode2SessionResponse code2Session(String jsCode) {
        String url = MessageFormat.format(URL_JSCODE_2_SESSION, wxLiteProperty.getAppId(), wxLiteProperty.getSecret(), jsCode);
        ResponseEntity<String> res = restTemplate.getForEntity(url, String.class);

        log.debug("http.status = '{}', body = {}", res.getStatusCode(), res.getBody());
        if (res.getStatusCode() != HttpStatus.OK) {
            log.error("调用微信 code2session 失败. res = {}", res);
            throw new BusinessException("调用微信 code2session 失败");
        }
        WxCode2SessionResponse result = new Gson().fromJson(res.getBody(), WxCode2SessionResponse.class);
        log.debug("result = {}", new Gson().toJson(result));
        if (result.getErrorCode() != null && result.getErrorCode() != Consts.RES_CODE_SUCCESS) {
            log.error("调用微信 code2session 失败. errorCode = {}, errorMsg = {}",
                    result.getErrorCode(), result.getErrorMsg());
            throw new BusinessException("调用微信 code2session 失败");
        }
        return result;
    }


    /**
     * 通过code换取网页授权公众号access_token
     *
     * @param code
     * @return
     */
    public WxMpOauthUserAccessToken getWxMpOauthUserToken(String code) {
        String url = MessageFormat.format(URL_WX_MP_OAUTH_ACCESS_TOKEN, wxMpProperty.getAppId(), wxMpProperty.getAppSecret(), code);
        ResponseEntity<String> res = restTemplate.getForEntity(url, String.class);
        log.debug("http.status = '{}', body = {}", res.getStatusCode(), res.getBody());
        if (res.getStatusCode() != HttpStatus.OK) {
            log.error("通过code换取网页授权access_token失败. code = {}, res = {}", code, res);
            throw new BusinessException("通过code换取网页授权access_toke失败n");
        }
        WxMpOauthUserAccessToken result = new Gson().fromJson(res.getBody(), WxMpOauthUserAccessToken.class);
        if (result.getErrorCode() != null && result.getErrorCode() != Integer.parseInt(Constants.ZERO)) {
            log.error("通过code换取网页授权access_token失败. code = {}, errorCode = {}, errorMsg = {}",
                    code, result.getErrorCode(), result.getErrorMsg());
            throw new BusinessException("通过code换取网页授权access_token失败");
        }
        log.debug("result = {}", new Gson().toJson(result));
        return result;

    }

    /**
     * 获得公众号用户信息
     *
     * @param accessToken
     * @param openId
     * @return
     */
    public WxUserBasicInfoVo getWxMpUserBasicInfo(String accessToken, String openId) {
        String url = MessageFormat.format(URL_GET_WX_MP_USER_BASIC_INFO, accessToken, openId);
        ResponseEntity<String> res = restTemplate.getForEntity(url, String.class);
        log.debug("http.status = '{}', body = {}", res.getStatusCode(), res.getBody());
        if (res.getStatusCode() != HttpStatus.OK) {
            log.error("获取微信公众号用户基本信息失败. openId = {}, res = {}", openId, res);
            throw new BusinessException("获取微信公众号用户基本信息失败");
        }
        WxUserBasicInfoVo result = new Gson().fromJson(res.getBody(), WxUserBasicInfoVo.class);
        if (result.getErrorCode() != null && result.getErrorCode() != Integer.parseInt(Constants.ZERO)) {
            log.error("获取微信公众号用户基本信息失败. openId = {}, errorCode = {}, errorMsg = {}",
                    openId, result.getErrorCode(), result.getErrorMsg());
            throw new BusinessException("获取微信公众号用户基本信息失败");
        }
        // TODO 斟酌用户信息是否需要保存到数据库
        log.debug("result = {}", new Gson().toJson(result));
        return result;
    }

    public String getAccessToken() {
        String accessTokenUrl = MessageFormat.format(URL_WX_LITE_ACCESS_TOKEN, wxMpProperty.getAppId(),
                wxMpProperty.getAppSecret());
        ResponseEntity<String> res = restTemplate.getForEntity(accessTokenUrl, String.class);

        log.debug("http.status = '{}', body = {}", res.getStatusCode(), res.getBody());
        if (res.getStatusCode() != HttpStatus.OK) {
            log.error("调用微信 URL_WX_LITE_ACCESS_TOKEN 失败. res = {}", res);
            throw new BusinessException("调用微信 URL_WX_LITE_ACCESS_TOKEN 失败");
        }
        WxAccessTokenResponse wxAccessTokenResponse = new Gson().fromJson(res.getBody(), WxAccessTokenResponse.class);
        return wxAccessTokenResponse.getAccessToken();
    }

}
